Skip to content

chore: rivetkit core/napi/typescript follow up review#4702

Closed
NathanFlurry wants to merge 1 commit into04-22-chore_fix_remaining_issues_with_rivetkit-corefrom
04-22-chore_rivetkit_core_napi_typescript_follow_up_review
Closed

chore: rivetkit core/napi/typescript follow up review#4702
NathanFlurry wants to merge 1 commit into04-22-chore_fix_remaining_issues_with_rivetkit-corefrom
04-22-chore_rivetkit_core_napi_typescript_follow_up_review

Conversation

@NathanFlurry
Copy link
Copy Markdown
Member

Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@railway-app
Copy link
Copy Markdown

railway-app Bot commented Apr 23, 2026

🚅 Deployed to the rivet-pr-4702 environment in rivet-frontend

Service Status Web Updated (UTC)
kitchen-sink ❌ Build Failed (View Logs) Web Apr 24, 2026 at 12:32 pm
website 😴 Sleeping (View Logs) Web Apr 23, 2026 at 3:00 pm
frontend-cloud ❌ Build Failed (View Logs) Web Apr 23, 2026 at 9:55 am
ladle ✅ Success (View Logs) Web Apr 23, 2026 at 9:55 am
frontend-inspector ❌ Build Failed (View Logs) Web Apr 23, 2026 at 9:54 am
mcp-hub ✅ Success (View Logs) Web Apr 23, 2026 at 3:55 am

Copy link
Copy Markdown
Member Author

NathanFlurry commented Apr 23, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 23, 2026

PR 4702 Code Review — Adversarial Review Synthesis

The full adversarial review findings (F1-F42) with challenger verdicts are in this comment. The per-diff code review is in the comment below.

Key findings verified as REAL in this PR:

  • F3: clean run exit fix (task.rs) - FIXED in this PR
  • F12: Registry.handler()/serve() throw - spec written (handler-serve-restoration.md), fix pending
  • F14: package exports subpaths removed - ./db and ./db/drizzle restored in this PR
  • F18: actor-lifecycle state in napi not core - tracked, not yet fixed
  • F19: inspector logic duplicated in TypeScript - tracked, not yet fixed
  • F21: 50ms polling loop in native.ts - tracked, not yet fixed
  • F32: module-level actor-keyed maps in native.ts - tracked, not yet fixed
  • F34: ActorContext.key type widened - tracked, not yet fixed
  • F35: sql on ctx but ./db dropped - ./db/drizzle restored in this PR
  • F36: ContextOf type helpers removed - tracked for restoration
  • F38: inline use in test - tracked
  • F41: dead BARE code audit - pending audit
  • F42: inline mod tests in src/ - policy added to CLAUDE.md

@NathanFlurry NathanFlurry changed the base branch from 04-22-chore_fix_remaining_issues_with_rivetkit-core to graphite-base/4702 April 23, 2026 04:02
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from 689feea to 527f1d2 Compare April 23, 2026 04:02
@NathanFlurry NathanFlurry changed the base branch from graphite-base/4702 to 04-22-chore_fix_remaining_issues_with_rivetkit-core April 23, 2026 04:02
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 23, 2026 04:02 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from 527f1d2 to ef109dd Compare April 23, 2026 08:02
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_fix_remaining_issues_with_rivetkit-core branch from a639b2e to d7cd40d Compare April 23, 2026 08:02
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 23, 2026 08:02 Destroyed
@claude
Copy link
Copy Markdown

claude Bot commented Apr 23, 2026

PR Review: chore: rivetkit core/napi/typescript follow up review

Overview

This is a substantial follow-up cleanup across rivetkit-core, NAPI, and TypeScript layers. Key additions:

  • New CoreServerlessRuntime in Rust (serverless.rs) — SSE-based serverless request handler
  • New runner_config.rs — auto-registers a local "normal" runner config on localhost endpoints
  • Hibernatable WebSocket support in the raw WebSocket handler
  • NAPI handleServerlessRequest and serverless config fields wired through JsServeConfig
  • Registry.handler() restored with native serverless implementation
  • rivetkit/db and rivetkit/db/drizzle entrypoints extracted as first-class exports
  • Expanded ActorKv typed API and several driver test fixes

Potential Bugs

1. Race condition in ensure_serverless_runtime (NAPI registry.rs)

// Request A and B both see None here simultaneously
if let Some(runtime) = self.serverless_runtime.lock().as_ref().cloned() {
    return Ok(runtime);
}
// Both proceed to take the registry — second caller gets "registry already serving"
let registry = { let mut guard = self.inner.lock(); guard.take()... };

Two concurrent requests on a cold serverless runtime can both see None, both try take(), and the second gets an error. Fix: combine the check and take under a single lock guard, or use a OnceCell/once_async pattern.

2. maybe_respond_to_raw_hibernatable_ack_state_probe — test protocol in production

fn maybe_respond_to_raw_hibernatable_ack_state_probe(...) -> bool {
    if env::var_os("VITEST").is_none() || message.binary {
        return false;
    }

Test-specific behavior is gated by a VITEST env var check inside the production receive loop. This adds a JSON parse attempt on every incoming text message when VITEST is set. Consider extracting this into a configurable test hook rather than embedding it in the hot path.

3. Sleep timer not reset on clean run exit (actor/task.rs)

When clean_exit && lifecycle == Started, the code returns None without calling self.ctx.reset_sleep_timer(). The sleep timer remains live after the run handler returns, so it could fire and trigger a sleep sequence while the actor is waiting for an engine-driven Stop. The test covers that stop dispatches cleanup, but does not verify the sleep timer is not still ticking.


Security

4. CORS reflects arbitrary origins with credentials: true (serverless.rs)

fn cors_headers(req: &ServerlessRequest) -> HashMap<String, String> {
    let origin = req.headers.get("origin").cloned()
        .unwrap_or_else(|| "*".to_owned());
    headers.insert("access-control-allow-credentials".to_owned(), "true".to_owned());

Reflecting any Origin header value with Access-Control-Allow-Credentials: true means any website can make authenticated cross-origin requests to this server. Typical remediation: maintain an explicit allowlist, or omit credentials: true when the origin is * / unknown.

5. clientToken exposed on the unauthenticated /metadata endpoint

if let Some(client_token) = &self.settings.client_token {
    object.insert("clientToken".to_owned(), json!(client_token));
}

/metadata has no authentication check — any caller can read clientToken. This appears intentional (the client SDK needs it for auto-configuration), but it should be documented and the token must be treated as public. If this token grants write/admin capability, it should be audience-restricted.


Code Quality

6. Backpressure in Registry.handler() should use antiox (registry/index.ts)

const backpressureWaiters: Array<() => void> = [];
const waitForBackpressure = async () => {
    await new Promise<void>((resolve) => { backpressureWaiters.push(resolve); });
};

This is an ad-hoc Promise queue. CLAUDE.md requires using antiox for TypeScript concurrency primitives (e.g. antiox/sync/mpsc) instead of custom channel wrappers.

7. sqlReturnsRows / hasMultipleStatements heuristics (db/drizzle.ts)

function sqlReturnsRows(query: string): boolean {
    // "WITH" branch catches all CTEs, including mutating ones without RETURNING
    return token.startsWith("WITH") || ...
}
function hasMultipleStatements(query: string): boolean {
    // Semicolons inside string literals or comments are false positives
    return trimmed.includes(";");
}

Both functions can be tripped by edge-case SQL. WITH ... DELETE without RETURNING will be treated as returning rows; semicolons in quoted strings trigger the multi-statement path. Acceptable for now, but worth flagging in migration docs.

8. bytes_response spawns a task per response (serverless.rs)

fn bytes_response(...) -> ServerlessResponse {
    let (tx, rx) = mpsc::channel(1);
    tokio::spawn(async move { let _ = tx.send(Ok(body)).await; });

This spawns a Tokio task to enqueue a single message on a channel with capacity 1. The send always completes without blocking, so the spawn is unnecessary overhead on every health/metadata/error response.


Minor Notes

  • serverless/configure.ts: Pool configuration failure is caught and logged but not re-thrown. If this silently fails on startup, the serverless deployment will accept requests that never get routed. The error message says "restart this process" but that guidance is only visible in logs.

  • normalize_regional_hostname in serverless.rs correctly normalizes api-{region}.rivet.dev → api.rivet.dev, consistent with CLAUDE.md.

  • drizzle-orm moved from devDependencies to dependencies — correct since rivetkit/db/drizzle is now a runtime export.

  • ensure_local_normal_runner_config has no retry logic. If the engine hasn't fully started when CoreRegistry::serve is called, the call fails hard. A brief retry loop for the local-dev case, or a note that the engine must be healthy before calling serve, would help.

  • Test assertion relaxations: Several startCount === 2 assertions were relaxed to toBeGreaterThanOrEqual(2). The fixture comment explains the reason, but tracking this pattern in future PRs is worthwhile to avoid masking restart-count regressions.


This review was updated on 2026-04-24.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 23, 2026

Preview packages published to npm

Install with:

npm install rivetkit@pr-4702

All packages published as 0.0.0-pr.4702.76b6c25 with tag pr-4702.

Engine binary is shipped via @rivetkit/engine-cli on linux-x64-musl, linux-arm64-musl, darwin-x64, and darwin-arm64. Windows users should use the release installer or set RIVET_ENGINE_BINARY.

Docker images:

docker pull rivetdev/engine:slim-76b6c25
docker pull rivetdev/engine:full-76b6c25
Individual packages
npm install rivetkit@pr-4702
npm install @rivetkit/react@pr-4702
npm install @rivetkit/rivetkit-napi@pr-4702
npm install @rivetkit/workflow-engine@pr-4702

@github-actions
Copy link
Copy Markdown
Contributor

Preview packages published to npm

Install with:

npm install rivetkit@pr-4702

All packages published as 0.0.0-pr.4702.d108c6a with tag pr-4702.

Engine binary is shipped via @rivetkit/engine-cli on linux-x64-musl, linux-arm64-musl, darwin-x64, and darwin-arm64. Windows users should use the release installer or set RIVET_ENGINE_BINARY.

Docker images:

docker pull rivetdev/engine:slim-d108c6a
docker pull rivetdev/engine:full-d108c6a
Individual packages
npm install rivetkit@pr-4702
npm install @rivetkit/react@pr-4702
npm install @rivetkit/rivetkit-napi@pr-4702
npm install @rivetkit/workflow-engine@pr-4702

@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 23, 2026 09:30 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from 9284ef8 to f7dae0a Compare April 23, 2026 09:53
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 23, 2026 09:53 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from f7dae0a to 69857a0 Compare April 23, 2026 23:23
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 23, 2026 23:24 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_fix_remaining_issues_with_rivetkit-core branch from 8c07fbd to fb56daa Compare April 24, 2026 10:19
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from 3b4d928 to 2a88f8f Compare April 24, 2026 10:19
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 24, 2026 10:19 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from 2a88f8f to d22906f Compare April 24, 2026 11:48
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 24, 2026 11:49 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from d22906f to 6d9c3e8 Compare April 24, 2026 12:14
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 24, 2026 12:14 Destroyed
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_fix_remaining_issues_with_rivetkit-core branch from 24be269 to cef23e2 Compare April 24, 2026 12:32
@NathanFlurry NathanFlurry force-pushed the 04-22-chore_rivetkit_core_napi_typescript_follow_up_review branch from 6d9c3e8 to 226d1d0 Compare April 24, 2026 12:32
@railway-app railway-app Bot temporarily deployed to rivet-frontend / rivet-pr-4702 April 24, 2026 12:32 Destroyed
@NathanFlurry
Copy link
Copy Markdown
Member Author

Landed in main via stack-merge fast-forward push. Commits are in main; closing to match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant